package com.redhat.redwork.widget.grid;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.opensymphony.xwork2.ActionSupport;

/**
 * unified grid request handler
 * @author Justin
 *
 */
public class GridAction extends ActionSupport implements ApplicationContextAware {

	private static final long	serialVersionUID = 5078264277068533593L;
	private static final Logger	log              = LoggerFactory.getLogger(GridAction.class);

	// the data!
	@SuppressWarnings("unchecked")
	private List				gridModel;
	private Object				object;
	private Object				criteria;
	// rows per page we want
	private Integer            	rows             = 15;
	// current page number
	private Integer            	page             = 0;
	// total page number
	private Integer            	total            = 0;
	// total records
	private Long            	record           = 0l;
	// sort order asc or desc
	private String             	sord;
	// sort column
	private String             	sidx;
	private ApplicationContext 	applicationContext;
	private String 				modelName;
	private String				id;
	private String[]			ids;

	public void setIds(String[] ids) {
		this.ids = ids;
	}

	/**
	 * list rows by page
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String index() {
		
		// try to get data model
		log.debug("use {}GridModel", modelName);
		GridModel model;
		try{
			model = (GridModel)applicationContext.getBean(modelName+"GridModel");
		}catch(Throwable t){
			log.error("grid model not found");
			return "NOT_FOUND";
		}
		
		// retrieve data from grid model
	    log.debug("page {}, {} rows, sort by '{}' {}", 
	    		new Object[]{getPage(), getRows(), getSidx(), getSord()});
	    List data = model.list(criteria, getPage(), getRows(), new Order(getSidx(), getSord()));
	    
	    setGridModel(data);
	    
	    setRecord(model.count(null));
	
	    long to = (getRows() * getPage());
	    long from = to - getRows();
	
	    if (to > getRecord()) to = getRecord();
	
	    setTotal((int) Math.ceil((double) getRecord() / (double) getRows()));
	
	    return SUCCESS;
	}
	
	/**
	 * fretch one row by given ID
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String show(){
		
		log.debug("show row {} in {}GridModel", id, modelName);
		
		GridModel model;
		try{
			model = (GridModel)applicationContext.getBean(modelName+"GridModel");
		}catch(Throwable t){
			log.error("grid model not found");
			return "NOT_FOUND";
		}
		object = model.get(id);
		
		return SUCCESS;
	}
	
	/**
	 * delete selected rows
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String delete(){
		
		log.debug("delete {} in {}GridModel", ids, modelName);

		GridModel model;
		try{
			model = (GridModel)applicationContext.getBean(modelName+"GridModel");
		}catch(Throwable t){
			log.error("grid model not found");
			return "NOT_FOUND";
		}
		
		if(ids != null && ids.length>0){
			// batch delete
			for(String id : ids){
				model.delete(id);
			}
		}else{
			// delete one
			model.delete(id);
		}
		
		return SUCCESS;
	}
	
	/**
	 * init the criteria object for forms
	 * @return
	 */
	public Object getCriteria() {
		
		if(criteria == null){
			GridModel model;
			try{
				model = (GridModel)applicationContext.getBean(modelName+"GridModel");
			}catch(Throwable t){
				log.error("grid model not found");
				return "NOT_FOUND";
			}
			
			criteria = model.getCriteriaObject();
		}
		
		return criteria;
	}

	public void setCriteria(Object criteria) {
		this.criteria = criteria;
	}


	/**
	 * @return how many rows we want to have into the grid
	 */
	public Integer getRows() {
		return rows;
	}
	
	/**
	 * @param rows
	 *            how many rows we want to have into the grid
	 */
	public void setRows(Integer rows) {
		this.rows = rows;
	}

	/**
	 * @return current page of the query
	 */
	public Integer getPage() {
		return page;
	}

	/**
	 * @param page
	 *            current page of the query
	 */
	public void setPage(Integer page) {
		this.page = page;
	}

	/**
	 * @return total pages for the query
	 */
	public Integer getTotal() {
		return total;
	}

	/**
	 * @param total
	 *            total pages for the query
	 */
	public void setTotal(Integer total) {
		this.total = total;
	}

	/**
	 * @return total number of records for the query. e.g. select count(*) from
	 *         table
	 */
	public Long getRecord() {
		return record;
	}

	/**
	 * @param record
	 *            total number of records for the query. e.g. select count(*)
	 *            from table
	 */
	public void setRecord(Long record) {

		this.record = record;

		if (this.record > 0 && this.rows > 0) {
			this.total = (int) Math.ceil((double) this.record
					/ (double) this.rows);
		} else {
			this.total = 0;
		}
	}

  /**
   * @return an collection that contains the actual data
   */
	@SuppressWarnings("unchecked")
	public List getGridModel() {
		return gridModel;
	}

  /**
   * @param gridModel
   *          an collection that contains the actual data
   */
	@SuppressWarnings("unchecked")
	public void setGridModel(List gridModel) {
		this.gridModel = gridModel;
	}

	/**
	 * @return sorting order
	 */
	public String getSord() {
		return sord;
	}

	/**
	 * @param sord
	 *            sorting order
	 */
	public void setSord(String sord) {
		this.sord = sord;
	}

	/**
	 * @return get index row - i.e. user click to sort.
	 */
	public String getSidx() {
		return sidx;
	}

	/**
	 * @param sidx
	 *            get index row - i.e. user click to sort.
	 */
	public void setSidx(String sidx) {
		this.sidx = sidx;
	}
	
	/**
	 * applicationContext auto inject
	 */
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	/**
	 * grid model name inject
	 * @param name
	 */
	public void setModelName(String name) {
		this.modelName = name;
	}
	
	/**
	 * the row intended to be showed
	 * @param id
	 */
	public void setId(String id) {
		this.id = id;
	}
}
